﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace Roton2.TextModeEmulation.Renderer
{
    public class ScreenRenderer : TextRenderer
    {
        AnsiChar[] buffer;
        int bufferLength;
        int screenHeight;
        int screenWidth;

        /// <summary>
        /// Create a ScreenRenderer with the specified dimensions.
        /// </summary>
        public ScreenRenderer(int screenWidth, int screenHeight)
            : base()
        {
            InitBuffer(screenWidth, screenHeight);
        }

        /// <summary>
        /// Create a ScreenRenderer with the specified screen and character dimensions, font and palette.
        /// </summary>
        public ScreenRenderer(int screenWidth, int screenHeight, int characterWidth, int characterHeight, byte[] font, Color[] palette) 
            : base(characterWidth, characterHeight, font, palette)
        {
            InitBuffer(screenWidth, screenHeight);
        }

        /// <summary>
        /// Returns the length of the screen buffer, in AnsiChars.
        /// </summary>
        public int BufferLength
        {
            get
            {
                return bufferLength;
            }
        }

        /// <summary>
        /// Returns true. ScreenRenderer has a screen buffer that can be read.
        /// </summary>
        public override bool CanRead
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Returns an array of AnsiChars copied from the screen buffer.
        /// </summary>
        /// <returns></returns>
        public AnsiChar[] GetBuffer()
        {
            AnsiChar[] result = new AnsiChar[bufferLength];
            Array.Copy(buffer, result, bufferLength);
            return result;
        }

        /// <summary>
        /// Returns an array of AnsiChars copied from the screen buffer at the specified offset, with the specified length.
        /// </summary>
        public AnsiChar[] GetBuffer(int offset, int length)
        {
            AnsiChar[] result = new AnsiChar[length];
            Array.Copy(buffer, offset, result, 0, length);
            return result;
        }

        /// <summary>
        /// Initialize the screen buffer.
        /// </summary>
        void InitBuffer(int screenWidth, int screenHeight)
        {
            this.screenHeight = screenHeight;
            this.screenWidth = screenWidth;
            this.bufferLength = screenWidth * screenHeight;
            this.buffer = new AnsiChar[bufferLength];
        }

        /// <summary>
        /// Read AnsiChar data at a specified location from the screen buffer.
        /// </summary>
        public override AnsiChar Read(int x, int y)
        {
            int index = x + (y * screenWidth);
            if (index >= 0 && index < bufferLength)
                return buffer[index];
            return new AnsiChar();
        }

        /// <summary>
        /// Refreshes the AnsiChar at the specified location.
        /// </summary>
        public void Refresh(int x, int y)
        {
            int index = x + (y * screenWidth);
            if (index >= 0 && index < bufferLength)
                base.Write(x, y, buffer[index]);
        }

        /// <summary>
        /// Set the screen buffer to the specified data.
        /// </summary>
        public void SetBuffer(AnsiChar[] data)
        {
            Array.Copy(data, buffer, bufferLength);
        }

        /// <summary>
        /// Write AnsiChar data at a specified location to the screen buffer.
        /// </summary>
        public override void Write(int x, int y, AnsiChar ac)
        {
            int index = x + (y * screenWidth);
            if (index >= 0 && index < bufferLength)
            {
                buffer[index] = ac;
                base.Write(x, y, ac);
            }
        }
    }
}
